﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Vitruvian.Serialization;
using Vitruvian.Serialization.Formatters;
using Vitruvian.Windows.Serialization.Formatters;
using Vitruvian.Logging;
using Vitruvian.Testing;

namespace SpotItComponents
{
    /// <summary>
    /// Game class
    /// 
    /// The server will create and manage games.  The client has no need to greate a Game object directly. 
    /// Also, since Games are not persistence, they do not be serializable
    /// </summary>
    public class Game
    {

        // Shared game information
        private GameInfo sharedGameInfo;

        // Server-only Info
        private object myLock = new object();
        private GameStateType state;
        private DateTime startTime;
        private DateTime? endTime;
        private Deck deck;
        private CardStack centerStack;

        private List<Session> players;
        private List<string> playerNames;
        private List<CardStack> playerHands;
        private List<GameMonitor> playerMonitors;

        public Game(Session firstPlayer, PlayingDeck playingDeck, Deck realDeck, GameType gameType, string title, int maxPlayers, GameMonitor firstPlayersMonitor)
        {
            sharedGameInfo = new GameInfo();

            sharedGameInfo.Title = title;
            sharedGameInfo.GameType = gameType;
            sharedGameInfo.MaxNumberOfPlayers = maxPlayers;
            sharedGameInfo.GameDeck = playingDeck;

            sharedGameInfo.PlayerNames = new List<string>(maxPlayers);
            sharedGameInfo.PlayerNames.Add(firstPlayer.UserInfo.FullName);
            sharedGameInfo.State = GameStateType.Created;

            startTime = DateTime.Now;
            endTime = null;
            deck = realDeck;

            centerStack = null;
            players = new List<Session>();
            playerNames = new List<string>();
            playerHands = new List<CardStack>();
            playerMonitors = new List<GameMonitor>();

            AddPlayer(firstPlayer, firstPlayersMonitor);
        }

        public GameInfo GameInfo
        {
            get { return sharedGameInfo; }
        }

        public List<string> PlayerNames
        {
            get { return playerNames; }
        }

        public bool AddPlayer(Session playerSession, GameMonitor monitor)
        {
            bool result = false;
            lock (myLock)
            {
                if (playerSession != null && players.Count < sharedGameInfo.MaxNumberOfPlayers && monitor != null )
                {
                    // Added the player to the game's data structures
                    players.Add(playerSession);
                    playerNames.Add(playerSession.UserInfo.FullName);
                    playerHands.Add(new CardStack());
                    playerMonitors.Add(monitor);

                    // Let the current player know that the game has been initialized
                    monitor.Initialize(this.GameInfo, players.Count-1, PlayerNames);

                    // Let all of the previous players know that a new player joined
                    for (int i = 0; i < players.Count - 1; i++)
                        playerMonitors[i].AddPlayer(playerSession.UserInfo.FullName);

                    result = true;
                }
            }
            return result;
        }

        public bool StartGame()
        {
            bool result = false;
            lock (myLock)
            {
                if (players.Count > 1 && state == GameStateType.Created)
                {
                    state = GameStateType.InProgress;

                    // TODO: Deal cards to players
                    
                    // TODO: Setup center stack

                    // TODO: Call Initialize for all Monitors
                    for (int i = 0; i < players.Count; i++)
                    {
                        List<CardStack> visibleCards = ComputeVisibleCards(i);
                        playerMonitors[i].Start(centerStack.TopCard, visibleCards);
                    }
                    result = true;
                }
            }
            return result;
        }

        private List<CardStack> ComputeVisibleCards(int forPlayerIndex)
        {
            List<CardStack> cardStackList = new List<CardStack>(playerHands.Count);
            for (int i=0; i<playerHands.Count; i++)
            {
                CardStack visibleHand = new CardStack();
                switch (this.GameInfo.GameType)
                {
                    // TODO: Update for other game types
                    case GameType.HotPotato:
                        visibleHand.AddCard(playerHands[i].TopCard);
                        break;
                    default:
                        if (i == forPlayerIndex)
                            visibleHand.AddCard(playerHands[i].TopCard);
                        break;
                }
            }
            return cardStackList;
        }
    }
}
